package cn.labbook.bluetooth.service.impl;

import cn.labbook.bluetooth.constant.AmmeterConstant;
import cn.labbook.bluetooth.constant.CommonConstant;
import cn.labbook.bluetooth.entity.*;
import cn.labbook.bluetooth.entity.wxpay.WXPay;
import cn.labbook.bluetooth.mapper.TransferRecordMapper;
import cn.labbook.bluetooth.pojo.vo.TencentOrderQueryVO;
import cn.labbook.bluetooth.service.*;
import cn.labbook.bluetooth.util.TimeUtils;
import cn.labbook.bluetooth.util.weixin.pay.PayUtil;
import cn.labbook.bluetooth.util.weixin.pay.UUIDHexGenerator;
import cn.labbook.bluetooth.util.weixin.pay.XmlUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Author: zhangyang
 * @Date: 2023/6/2 18:04
 * @Desc: 转账记录 service 实现
 */
@Slf4j
@Service
public class TransferRecordServiceImpl extends ServiceImpl<TransferRecordMapper, TransferRecord> implements ITransferRecordService {

    private final static String mch_id = "1491927112";

    private final static String spbill_create_ip = "127.0.0.1";

    private final String notify_url = "https://bluetooth.zoercn.com/bluetooth/weixin/paycallback.do";

    private final String trade_type = "JSAPI";

    private final String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    private final static String key = "&key=zk123sqweqdsadZK9120392018490184";

    private final static String appid = "wxafeeae8c758d838d";

    @Autowired
    private IAmmeterService ammeterService;
    @Autowired
    private ITenantPayService tenantPayService;
    @Autowired
    private IAdminService adminService;
    @Autowired
    private IUserService userService;


    @Override
    public synchronized boolean transfer(TenantPay tenantPay) {
        log.info("转账业务开始-----------------tenantPay:" + tenantPay.toString());

        if (exist(tenantPay.getTenantPayId())) {
            updateTenantPayFail(tenantPay.getTenantPayId(), "已转过账");
            log.error("已转过账----------------------tenantPayId:" + tenantPay.getTenantPayId());
            return false;
        }

        TencentOrderQueryVO queryVO = orderQuery(tenantPay.getTenantPayId());
        if (!Objects.equals(TencentOrderQueryVO.SUCCESS_CODE, queryVO.getResult_code()) ||
                !Objects.equals(TencentOrderQueryVO.SUCCESS_CODE, queryVO.getReturn_code())) {
            updateTenantPayFail(tenantPay.getTenantPayId(), "查询支付记录失败");
            log.error("查询支付记录失败----------------------tenantPayId:" + tenantPay.getTenantPayId());
            return false;
        }
        if (!Objects.equals(TencentOrderQueryVO.SUCCESS_CODE, queryVO.getTrade_state())) {
            updateTenantPayFail(tenantPay.getTenantPayId(), "支付未成功");
            log.error("支付未成功----------------------tenantPayId:" + tenantPay.getTenantPayId());
            return false;
        }
        // 单位为分
        Double payAmount = Double.parseDouble(queryVO.getCash_fee()) / 100;
        if (!Objects.equals(payAmount, tenantPay.getPayAmouont())) {
            updateTenantPayFail(tenantPay.getTenantPayId(), "金额校验失败,微信方金额为：" + payAmount);
            log.error("金额校验失败----------------------tenantPayId:" + tenantPay.getTenantPayId() + ",payAmount=" + payAmount);
            return false;
        }

        WXPay wxPay = new WXPay();
        double rate = getNowPrice(tenantPay.getAmmeterId());
        double total_fee = tenantPay.getPayAmouont() * (100.0D - rate) / 100.0D;
        double total_fee3 = tenantPay.getPayAmouont() / (100.0D + rate) * 100.0D * 100.0D;
        BigDecimal bigDecimal = (new BigDecimal(total_fee)).multiply(new BigDecimal(100)).setScale(0, 4);
        LambdaQueryWrapper<Ammeter> lambda1 = (new QueryWrapper()).lambda();
        lambda1.eq(Ammeter::getAmmeterId, tenantPay.getAmmeterId());
        Ammeter one = this.ammeterService.getOne(lambda1);
        if (one.getIsSkimp() == AmmeterConstant.IsSkimp.YES) {
            wxPay.setAmount((new BigDecimal(total_fee3)).setScale(0, 4).toString());
        } else {
            wxPay.setAmount(bigDecimal.toString());
        }

        wxPay.setMch_appid(appid);
        wxPay.setMchid(mch_id);
        wxPay.setDesc("佐客房客电费充值");
        wxPay.setNonce_str(UUIDHexGenerator.generate());
        LambdaQueryWrapper<User> lambda = (new QueryWrapper()).lambda();
        lambda.eq(User::getAdminId, one.getManagerId());
        wxPay.setOpenid(this.userService.getOne(lambda).getOpenId());
        wxPay.setPartner_trade_no(tenantPay.getTenantPayId());
        wxPay.setCheck_name("NO_CHECK");
        wxPay.setSpbill_create_ip(spbill_create_ip);
        Map<String, Object> sParaTemp = new HashMap<>();
        sParaTemp.put("mch_appid", wxPay.getMch_appid());
        sParaTemp.put("mchid", wxPay.getMchid());
        sParaTemp.put("nonce_str", wxPay.getNonce_str());
        sParaTemp.put("partner_trade_no", wxPay.getPartner_trade_no());
        sParaTemp.put("amount", wxPay.getAmount());
        sParaTemp.put("spbill_create_ip", wxPay.getSpbill_create_ip());
        sParaTemp.put("check_name", wxPay.getCheck_name());
        sParaTemp.put("desc", wxPay.getDesc());
        sParaTemp.put("openid", wxPay.getOpenid());
        Map sPara = PayUtil.paraFilter(sParaTemp);
        String prestr = PayUtil.createLinkString(sPara);
        String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
        wxPay.setSign(mysign);
        String respXml = XmlUtil.messagePayToXML(wxPay);
        respXml = respXml.replace("__", "_");
        String param = respXml;
        String result = PayUtil.ssl("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers", param);
        Map<Object, Object> map = new HashMap<>();
        InputStream in = new ByteArrayInputStream(result.getBytes());
        SAXReader reader = new SAXReader();
        Document document;
        try {
            document = reader.read(in);
        } catch (DocumentException e) {
            log.error("转账异常----------------" + e.getMessage());
            throw new RuntimeException(e);
        }

        Element root = document.getRootElement();
        List<Element> elementList = root.elements();
        for (Element element : elementList)
            map.put(element.getName(), element.getText());

        log.info(map.toString());
        String return_code = map.get("return_code").toString();
        String result_code = map.get("result_code").toString();
        if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
            success(tenantPay);
            log.info("企业付款成功,user表状态改变失败");
            return true;
        }

        String err_code_des = map.get("err_code_des").toString();
        fail(tenantPay, err_code_des);
        log.info("重试-企业付款失败");
        return false;
    }

    private void updateTenantPayFail(String tenantPayId, String failReason) {
        TenantPay _update = tenantPayService.getById(tenantPayId);
        _update.setRemark("次日到账");
        _update.setFailReason(failReason);
        tenantPayService.updateById(_update);
    }

    private void fail(TenantPay tenantPay, String failReason) {
        // 保存转账记录
        TransferRecord transferRecord = new TransferRecord();
        transferRecord.setTenantPayId(tenantPay.getTenantPayId());
        transferRecord.setAmount(tenantPay.getManagerAmount());
        transferRecord.setIsDeleted(CommonConstant.NO);
        transferRecord.setCt(new Date());
        transferRecord.setStatus(TransferRecord.Status.FAIL.getKey());
        transferRecord.setFailReason(failReason);
        save(transferRecord);

        updateTenantPayFail(tenantPay.getTenantPayId(), failReason);
    }

    private void success(TenantPay tenantPay) {
        // 保存转账记录
        TransferRecord transferRecord = new TransferRecord();
        transferRecord.setTenantPayId(tenantPay.getTenantPayId());
        transferRecord.setAmount(tenantPay.getManagerAmount());
        transferRecord.setIsDeleted(CommonConstant.NO);
        transferRecord.setCt(new Date());
        transferRecord.setStatus(TransferRecord.Status.SUCCESS.getKey());
        save(transferRecord);

        // 更新支付记录
        TenantPay _update = tenantPayService.getById(tenantPay.getTenantPayId());
        _update.setRemark("");
        _update.setIsArrive(0);
        _update.setManagerTransferTime(TimeUtils.dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss"));
        _update.setManagerTransferOrderNo(tenantPay.getTenantPayId());
        tenantPayService.updateById(_update);
    }

    private boolean exist(String tenantPayId) {
        LambdaQueryWrapper<TransferRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TransferRecord::getTenantPayId, tenantPayId);
        wrapper.eq(TransferRecord::getStatus, TransferRecord.Status.SUCCESS.getKey());
        return count(wrapper) != 0;
    }

    public double getNowPrice(String ammeterId) {
        LambdaQueryWrapper<Ammeter> lambda1 = (new QueryWrapper()).lambda();
        lambda1.eq(Ammeter::getAmmeterId, ammeterId);
        Ammeter one = this.ammeterService.getOne(lambda1);
        LambdaQueryWrapper<Admin> lambda2 = (new QueryWrapper()).lambda();
        lambda2.eq(Admin::getAdminId, one.getAdminId());
        Admin one1 = this.adminService.getOne(lambda2);
        return one1.getPayRate();
    }

    public static void main(String[] args) {
        // System.out.println(orderQuery("14919271122023060205523031022867"));
    }

    /**
     * 支付订单查询
     *
     * @param tenantPayId       支付单号
     * @return                  查询结果
     */
    public TencentOrderQueryVO orderQuery(String tenantPayId) {
        log.info("支付订单查询----------------tenantPayId=" + tenantPayId);
        WXPay wxPay = new WXPay();
        wxPay.setAppid(appid);
        wxPay.setMch_id(mch_id);
        wxPay.setNonce_str(UUIDHexGenerator.generate());
        wxPay.setOut_trade_no(tenantPayId);

        Map<String, Object> sParaTemp = new HashMap<>();
        sParaTemp.put("appid", wxPay.getAppid());
        sParaTemp.put("mch_id", wxPay.getMch_id());
        sParaTemp.put("nonce_str", wxPay.getNonce_str());
        sParaTemp.put("out_trade_no", tenantPayId);
        Map sPara = PayUtil.paraFilter(sParaTemp);
        String prestr = PayUtil.createLinkString(sPara);
        String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
        wxPay.setSign(mysign);
        String respXml = XmlUtil.messagePayToXML(wxPay);
        respXml = respXml.replace("__", "_");
        String param = respXml;
        String result = PayUtil.ssl("https://api.mch.weixin.qq.com/pay/orderquery", param);
        Map<String, String> map = new HashMap<>();
        InputStream in = new ByteArrayInputStream(result.getBytes());
        SAXReader reader = new SAXReader();
        Document document;
        try {
            document = reader.read(in);
        } catch (DocumentException e) {
            e.printStackTrace();
            log.info("支付订单查询失败----------------tenantPayId=" + tenantPayId + ",errorMessage=" + e.getMessage());
            return new TencentOrderQueryVO();
        }
        Element root = document.getRootElement();
        List<Element> elementList = root.elements();
        for (Element element : elementList)
            map.put(element.getName(), element.getText());

        log.info("支付订单查询----------------tenantPayId=" + tenantPayId + ",map=" + map);

        TencentOrderQueryVO queryVO = new TencentOrderQueryVO();
        queryVO.setReturn_code(map.get("return_code"));
        queryVO.setResult_code(map.get("result_code"));
        queryVO.setTrade_state(map.get("trade_state"));
        queryVO.setCash_fee(map.get("total_fee"));
        return queryVO;
    }

}
